package controlador;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import logica.Atributo;
import logica.AtributoSimple;
import logica.AtributoSimpleException;

import vista.objetos.AtributoGraficable;
import vista.objetos.AtributoTipoNoSoportadoException;
import vista.objetos.FabricaAtributoGraficable;
import vista.objetos.FabricaAtributoGraficableCalculo;
import vista.objetos.FabricaAtributoGraficableCaracterizacion;
import vista.objetos.FabricaAtributoGraficableCompuesto;
import vista.objetos.FabricaAtributoGraficableCopia;
import vista.objetos.FabricaEntidadGraficable;
import vista.objetos.FabricaEntidadGraficableCosa;
import vista.objetos.FabricaEntidadGraficableDominio;
import vista.objetos.FabricaEntidadGraficableHistorica;
import vista.objetos.FabricaEntidadGraficableProgramada;
import vista.objetos.FabricaRelacionGraficable;
import vista.objetos.FabricaRelacionGraficableAsociacion;
import vista.objetos.FabricaRelacionGraficableComposicion;

public class ControladorDeTiposDeObjetos implements IConversorLogicoAGraficable{

	private List<FabricaEntidadGraficable> tiposDeEntidadesGraficables = new LinkedList<FabricaEntidadGraficable>();
	private List<FabricaRelacionGraficable> tiposDeRelacionesGraficables =  new LinkedList<FabricaRelacionGraficable>();
	private List<FabricaAtributoGraficable> tiposDeAtributosGraficables = new LinkedList<FabricaAtributoGraficable>();

	private static ControladorDeTiposDeObjetos instancia = new ControladorDeTiposDeObjetos();
	
	public static ControladorDeTiposDeObjetos getInstancia(){
		return instancia;
	}	
	
	private ControladorDeTiposDeObjetos()
	{
		inicializarTiposDeEntidadesGraficables();
		inicializarTiposDeRelacionesGraficables();
		inicializarTiposDeAtributosGraficables();
	}
	
	private void inicializarTiposDeEntidadesGraficables() 
	{
		tiposDeEntidadesGraficables.add(new FabricaEntidadGraficableCosa());
		tiposDeEntidadesGraficables.add(new FabricaEntidadGraficableDominio());
		tiposDeEntidadesGraficables.add(new FabricaEntidadGraficableHistorica());
		tiposDeEntidadesGraficables.add(new FabricaEntidadGraficableProgramada());
	}
	
	public List<FabricaEntidadGraficable> getTipoDeEntidades(){
		return tiposDeEntidadesGraficables;
	}
	
	private void inicializarTiposDeRelacionesGraficables()
	{
		tiposDeRelacionesGraficables.add(new FabricaRelacionGraficableAsociacion());
		tiposDeRelacionesGraficables.add(new FabricaRelacionGraficableComposicion());
	}
	
	public List<FabricaRelacionGraficable> getTipoDeRelaciones() {
		return tiposDeRelacionesGraficables;
	}
	
	private void inicializarTiposDeAtributosGraficables() 
	{
		tiposDeAtributosGraficables.add(new FabricaAtributoGraficableCaracterizacion());
		tiposDeAtributosGraficables.add(new FabricaAtributoGraficableCopia());
		tiposDeAtributosGraficables.add(new FabricaAtributoGraficableCalculo());
	}
	
	public List<FabricaAtributoGraficable> getTipoDeAtributos() {
		return tiposDeAtributosGraficables;
	}

	/** Atributo Lógico --> Atributo Graficable
	 * Dada una lista de Atributos Lógicos retorna la lista de los Atributos Graficables
	 * con sus correspondientes referencias.
	 */
	public List<AtributoGraficable> getAtributoGraficables(List<Atributo> atributosLogicos) throws AtributoTipoNoSoportadoException
	{
		List<AtributoGraficable> atriGraf = new LinkedList<AtributoGraficable>();
		List<FabricaAtributoGraficable> tiposAtributos = this.getTipoDeAtributos();
		
		for (Atributo atributo: atributosLogicos)
			crearAtributoGraficable(atriGraf, tiposAtributos, atributo);
		
		return atriGraf;
	}

	private void crearAtributoGraficable(List<AtributoGraficable> atriGraf, List<FabricaAtributoGraficable> tiposAtributos, Atributo atributo) throws AtributoTipoNoSoportadoException
	{	
		try {	
			atriGraf.add((new FabricaAtributoGraficableCompuesto()).crearAtributoGraficable(atributo));
		}
		catch(AtributoSimpleException noEraCompuesto)
		{
			AtributoSimple esSimple = (AtributoSimple) atributo;
			atriGraf.add(this.crearAtributoGaficableSimple(esSimple, tiposAtributos));				
		}
	}
	
	private AtributoGraficable crearAtributoGaficableSimple(AtributoSimple atributo, List<FabricaAtributoGraficable> tiposAtributos) throws AtributoTipoNoSoportadoException
	{
		Iterator<FabricaAtributoGraficable> itTipoAtributo = tiposAtributos.iterator();
		
		while(itTipoAtributo.hasNext())
		{
			FabricaAtributoGraficable fabrica = (FabricaAtributoGraficable) itTipoAtributo.next();
			
			if(atributo.getTipo().compareToIgnoreCase(fabrica.toString()) == 0)
				try {
					return fabrica.crearAtributoGraficable(atributo);
				} catch (AtributoSimpleException e) { // se supone q no debería pasar, porque si salta esta excepción es una atributo compuesto
					e.printStackTrace();
				}
		}
		
		throw new AtributoTipoNoSoportadoException("El tipo " + atributo.getTipo() + " no es soportado por la aplicacion.");
		
	}
}
